package com.joinway.admin.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.joinway.admin.bean.view.Ddl2CodeColumn;
import com.joinway.admin.bean.view.Sql2BeanView;
import com.joinway.admin.bean.view.Sql2CodeView;
import com.joinway.admin.bean.view.Sql2PageView;
import com.joinway.admin.service.AppService;
import com.joinway.admin.service.AutoCodeService;
import com.joinway.framework.admin.bean.UserContext;
import com.joinway.framework.admin.core.constant.AdminWebConstants;
import com.joinway.framework.bean.logging.annotation.InputLog;
import com.joinway.framework.bean.logging.annotation.LogIgnore;
import com.joinway.framework.extension.groovy.DomainUtils;
import com.joinway.framework.extension.utils.DataUtils;
import com.joinway.framework.support.input.annotation.Render;
import com.joinway.framework.support.input.type.Case;
import com.joinway.framework.text.java.JavaBuilder;
import com.joinway.framework.text.java.JavaField;
import com.joinway.framework.text.sql.DdlParser;
import com.joinway.framework.text.sql.bean.Column;
import com.joinway.framework.text.sql.bean.Table;
import com.joinway.framework.text.ui.UIBuilder;
import com.joinway.platform.bean.AdminPageConfig;
import com.joinway.platform.bean.AdminPageItem;
import com.joinway.platform.bean.CodeHistoryItem;
import com.joinway.platform.bean.domain.AutocodeHistory;
import com.joinway.platform.constant.CodeConstants;
import com.joinway.platform.utils.AutoCodeHelper;
import com.joinway.platform.utils.DdlEntity;

@Controller
@RequestMapping("page")
@Validated
public class AutoCodeWebController {

	private final static Logger log = LoggerFactory.getLogger(AutoCodeWebController.class);
	
	final static String MASK_SUFFIX = "mask";
	final static String FORMAT_SUFFIX = "format";
	final static String DATE_SUFFIX = "date";
	
	@Autowired AutoCodeService service;
	
	@Autowired AppService appService;
	
	@RequestMapping(value="ddl2bean_step2")
	@InputLog
	public ModelAndView parseDdl4Bean(@RequestParam("ddl") String ddl) throws Exception {
		ModelAndView mv = new ModelAndView("page/ddl2bean_step2");
		
		Table table = DdlParser.parse(ddl);
//		DdlEntity entity = new DdlEntity(ddl);
		List<JavaField> columns = JavaBuilder.buildJavaFields(table.getColumns());
//		entity.getFields().stream().filter(f -> !f.isIdKey()).forEach(f -> columns.add(f.getColumn()));
//		table.getColumns().stream().forEach(f -> columns.add(f.getName()));
		mv.addObject("columns", columns);
		
		return mv;
	}

	@RequestMapping(value="ddl2bean_step3")
	@InputLog
	public ModelAndView createDomainBean(
			@RequestParam(value="domainModule",required=false,defaultValue="common") @Render(format=Case.Lower) String domainModule
			, @RequestParam("ddl") String ddl
			, @LogIgnore HttpServletRequest request
	) throws Exception {
		ModelAndView mv = new ModelAndView("page/ddl2bean_step3");
		
		Map<String, String> masks = new HashMap<>();
		Map<String, String> formats = new HashMap<>();
		Map<String, String> dates = new HashMap<>();
		
		Iterator<String> keys = request.getParameterMap().keySet().iterator();
		while(keys.hasNext()){
			String key = keys.next();
			String[] arr = StringUtils.split(key, ".");
			
			if(ArrayUtils.getLength(arr) < 2) continue;
			
			String value = request.getParameterMap().get(key)[0];
			
			if(StringUtils.isNotBlank(value)){
				if(MASK_SUFFIX.equalsIgnoreCase(arr[1])){
					masks.put(arr[0], value);
				}else if(FORMAT_SUFFIX.equalsIgnoreCase(arr[1])){
					formats.put(arr[0], value);
				}else if(DATE_SUFFIX.equalsIgnoreCase(arr[1]) && StringUtils.isNotBlank(value)){
					dates.put(arr[0], value);
				}
			}
		}
		
		Sql2BeanView view = service.convertDdlToBean(domainModule, ddl, masks, formats, dates);
		
		mv.addObject("module", domainModule);
		mv.addObject("bean", view.getDomainBeanName());
		mv.addObject("preview", view.getDomainBeanPreviewUrl());
		mv.addObject("download", view.getDomainBeanDownloadUrl());
		
		return mv;
	}

	@RequestMapping(value="ddl2code_step2")
	@InputLog
	public ModelAndView parseDdl4Code(@RequestParam("ddl") @LogIgnore String ddl) throws Exception {
		ModelAndView mv = new ModelAndView("page/ddl2code_step2");
		
		DdlEntity entity = new DdlEntity(ddl);
		List<Ddl2CodeColumn> columns = new ArrayList<>();
		
		entity.getFields().stream().filter(f -> !f.isIdKey()).forEach(f -> {
			String equal = "checked";
			String like = "";
			
			if("Date".equals(f.getType())){
				equal = "";
				like = "checked";
			}
			
			String type = AutoCodeHelper.getJavaType(f);
			
			columns.add(new Ddl2CodeColumn(f.getColumn(), type, equal, like));
		});
		
		mv.addObject("columns", columns);
		
		return mv;
	}

	@RequestMapping(value="ddl2code_step3")
	@InputLog
	public ModelAndView createDdlCode(
			@RequestParam(value="domainModule",required=false,defaultValue="common") @Render(format=Case.Lower) String domainModule
			, @RequestParam(value="mapperModule",required=false,defaultValue="mobile") @Render(format=Case.Lower) String mapperModule
			, @RequestParam("ddl") @LogIgnore String ddl
			, @LogIgnore HttpServletRequest request
	) throws Exception {
		ModelAndView mv = new ModelAndView("page/ddl2code_step3");
		
		List<String> params = Arrays.asList(request.getParameterMap().keySet().stream().toArray(String[]::new));
		
		List<String> columns = Arrays.asList(
				params.stream()
					.filter(f -> !f.equals("domainModule") && !f.equals("mapperModule") && !f.equals("ddl") && !f.endsWith(".query") )
					.toArray(String[]::new)
		);
		
		Map<String, String> conditions = new HashMap<>();
		for(String p : params){
			if(!p.equals("domainModule") && !p.equals("mapperModule") && !p.equals("ddl") && p.endsWith(".query")){
				String[] arr = StringUtils.split(p, ".");
				if(columns.contains(arr[0])){
					String value = request.getParameter(p);
					conditions.put(arr[0], value);
				}
			}
		}
		
		Sql2CodeView view = service.convertDdlToCode(domainModule, mapperModule, ddl, columns, conditions);
		
		mv.addObject("xml", view.getMybatisXmlName());
		mv.addObject("previewXml", view.getMybatisXmlPreviewUrl());
		mv.addObject("downloadXml", view.getMybatisXmlDownloadUrl());
		
		mv.addObject("module", mapperModule);
		mv.addObject("dao", view.getDaoName());
		mv.addObject("previewDao", view.getDaoPreviewUrl());
		mv.addObject("downloadDao", view.getDaoDownloadUrl());
		
		mv.addObject("repo", view.getDaoRepositoryName());
		mv.addObject("previewRepo", view.getDaoRepositoryPreviewUrl());
		mv.addObject("downloadRepo", view.getDaoRepositoryDownloadUrl());
		
		return mv;
	}

	@RequestMapping(value="ddl2page_step2")
//	@InputLog
	public ModelAndView parseDdl4Page(@RequestParam("ddl") String ddl, @LogIgnore HttpServletRequest request) throws Exception {
		UserContext context = (UserContext)request.getSession().getAttribute(AdminWebConstants.USER_CONTEXT_KEY);
		
		ModelAndView mv = new ModelAndView("page/ddl2page_step2");
		
		Table table = DdlParser.parse(ddl);
		
//		DdlEntity entity = new DdlEntity(ddl);
		List<Ddl2CodeColumn> codeColumns = new ArrayList<>();
		
		List<Column> columns = table.getColumns();
		for(Column column : columns){
			String type =  UIBuilder.buildFieldType(JavaBuilder.buildJavaType(column));
			Ddl2CodeColumn codeColumn = new Ddl2CodeColumn();
			
			codeColumn.setName(DomainUtils.convertToDomainFieldName(column.getName()));
			
			String comment = column.getComment();
			
			if(StringUtils.isBlank(comment)){
				codeColumn.setComment("");
			}else{
				codeColumn.setComment(comment);
			}
//			column.setId(field.isIdKey());
			codeColumn.setCategory(type);
			
			codeColumns.add(codeColumn);
		}
		
		mv.addObject("columns", codeColumns);
		String tableName = table.getName();
		mv.addObject("tableName", tableName);
/*		
		List<AutocodeHistory> histories = appService.findAutocodeHistories(tableName, CodeConstants.CodeType.Page, context.getUser().getLoginName());
		if(histories != null){
			List<CodeHistoryItem> items = new ArrayList<>();
			
			for(AutocodeHistory history : histories){
				CodeHistoryItem item = new CodeHistoryItem();
				item.setId(history.getId());
				item.setAuthor(history.getUpdateBy());
				item.setTime(DateFormatUtils.format(history.getUpdateDate(), "yyyy-MM-dd HH:mm:ss"));
				
				items.add(item);
			}
			
			mv.addObject("histories", items);
		}
*/		
		return mv;
	}

	@RequestMapping(value="ddl2page_step3")
	@InputLog
	public ModelAndView createDdlPage(
			@RequestParam("ddl") @LogIgnore String ddl
			, @RequestParam(value="add",required=false,defaultValue="false") String add
			, @RequestParam(value="update",required=false,defaultValue="false") String update
			, @RequestParam(value="clone",required=false,defaultValue="false") String clone
			, @RequestParam(value="delete",required=false,defaultValue="false") String delete
			, @RequestParam(value="export",required=false,defaultValue="false") String export
			, @RequestParam(value="import",required=false,defaultValue="false") String emport
			, @RequestParam(value="maxColumn",required=false,defaultValue="3") String maxColumn
			, @RequestParam(value="overrided",required=false,defaultValue="false") String overrided
			, @RequestParam(value="module",required=false,defaultValue="common") String module
			, @LogIgnore HttpServletRequest request
	) throws Exception {
		ModelAndView mv = new ModelAndView("page/ddl2page_step3");
		
		List<AdminPageItem> items = new ArrayList<>();
		
		/* get column name parameter */
		Iterator<String> keys = request.getParameterMap().keySet().iterator();
		while(keys.hasNext()){
			String key = keys.next();
			if(key.endsWith("_name")){
				String columnName = request.getParameter(key);
				AdminPageItem item = new AdminPageItem(columnName);
				item.setVisible(StringUtils.isBlank(request.getParameter(columnName + "_page")));
				items.add(item);
			}
		}
		
		for(AdminPageItem item : items){
			String columnName = item.getColumn();
			item.setQuery(DataUtils.convertBool(request.getParameter(columnName + ".query")));
			item.setRequired(DataUtils.convertBool(request.getParameter(columnName + ".required")));
			item.setText(request.getParameter(columnName + ".text"));
			item.setOrder(request.getParameter(columnName + ".order"));
			item.setOrderNo(DataUtils.convertToInt(request.getParameter(columnName + ".orderNo")));
			item.setCategory(request.getParameter(columnName + ".category"));
			item.setEditable(DataUtils.convertBool(request.getParameter(columnName + ".editable")));
			item.setMin(request.getParameter(columnName + ".min"));
			item.setMax(request.getParameter(columnName + ".max"));
			item.setPrecision(request.getParameter(columnName + ".precision"));
			item.setList(request.getParameter(columnName + ".list"));
		}
		
		AdminPageConfig config = new AdminPageConfig();
		config.setAdd(DataUtils.convertBool(add));
		config.setUpdate(DataUtils.convertBool(update));
		config.setDelete(DataUtils.convertBool(delete));
		config.setExport(DataUtils.convertBool(export));
		config.setEmport(DataUtils.convertBool(emport));
		config.setClone(DataUtils.convertBool(clone));
		config.setMaxColumn(DataUtils.convertToInt(maxColumn));
		config.setOverrided(DataUtils.convertBool(overrided));
		config.setModule(module);
		
		Sql2PageView view = service.convertDdlToPage(ddl, items, config);
		
		mv.addObject("page", view.getPageName());
		mv.addObject("preview", view.getPreviewUrl());
		mv.addObject("download", view.getDownloadUrl());
		mv.addObject("localFile", StringUtils.replace(view.getLocalFile(), "\\", "\\\\"));
		mv.addObject("code", view.getServiceName());
		mv.addObject("codePreview", view.getServicePreviewUrl());
		mv.addObject("codeDownload", view.getServiceDownloadUrl());
		mv.addObject("overrided", DataUtils.convertBool(overrided));
		mv.addObject("path", StringUtils.trimToEmpty(view.getLocalFile()).replaceAll("/+", "\\\\").replaceAll("\\\\+", "\\\\"));
		
		String file = "file:///" + StringUtils.trimToEmpty(view.getLocalFile()).replaceAll("/+", "/").replaceAll("\\\\+", "/");
		mv.addObject("file", file);

		//mv.addObject("rnd", UUID.randomUUID().toString().split("-")[0]);
		
		return mv;
	}
}
